from sys import exit
from PyMasterMindGraphic import*
from random import choice
from socket import *
from time import sleep
from threading import Timer

pygame.init()
screen = pygame.display.set_mode((776, 747), 0, 32)
pygame.display.set_caption("PYMASTER MIND")

pygame.mouse.set_visible(False)
button_pressed = False

buttons = {}
buttons['single_player'] = Button('imagens/singleplayer.png', 'imagens/startgame.png', (30, 250))
buttons['multi_player'] = Button('imagens/multiplayer.png', 'imagens/multiplayer_mouse.png', (30, 310))
buttons['how_to_play'] = Button('imagens/howtoplay.png', 'imagens/howtoplay_mouse.png', (30, 370))
buttons['thegame'] = Button('imagens/thegame.png', 'imagens/thegame_mouse.png', (30,430))
buttons['credits'] = Button('imagens/credits.png', 'imagens/credits_mouse.png', (30,490))
buttons['quit'] = Button('imagens/quit.png', 'imagens/quit_mouse.png', (30,550))

background = pygame.image.load('imagens/screen.png').convert()
mouse_cursor = pygame.image.load('imagens/mouse.png').convert_alpha()
background_play = pygame.image.load('imagens/screen_play.png').convert()
background_how = pygame.image.load('imagens/screen_how.png').convert()
background_thegame = pygame.image.load('imagens/screen_thegame.png').convert()
background_credits = pygame.image.load('imagens/screen_credits.png').convert()

GraphicPines = {}
GraphicPines['blue'] = GraphicPine('blue', 'imagens/pine_blue.png', (0,0))
GraphicPines['red'] = GraphicPine('red', 'imagens/pine_red.png', (0,0))
GraphicPines['green'] = GraphicPine('green', 'imagens/pine_green.png', (0,0))
GraphicPines['pink'] = GraphicPine('pink', 'imagens/pine_pink.png', (0,0))
GraphicPines['metal'] = GraphicPine('metal', 'imagens/pine_metal.png', (0,0))
GraphicPines['lilac'] = GraphicPine('lilac', 'imagens/pine_lilac.png', (0,0))
GraphicPines['colors'] = GraphicPine('colors', 'imagens/pine_colors.png', (0,0))
GraphicPines['orange'] = GraphicPine('orange', 'imagens/pine_orange.png', (0,0))

def print_display(msg, font, color, cord):
    impri = font.render(msg, True, color)
    screen.blit(impri, cord)
    return impri.get_size()

def input_display(msg, font, color, cord):
    answer = []
    while True: 
        screen.blit(background, (0,0))
        size = print_display(msg, font, color, cord)
    
        event = pygame.event.wait()
    
        if event.type == KEYDOWN:
    
            if event.key == K_BACKSPACE:
                try:
                    answer.pop()
                except IndexError:
                    pass
            
            elif event.key == K_RETURN:
                return ''.join(answer)
            
            else:
                try:
                    answer.append(chr(event.key))
                except ValueError:
                    pass

        print_display(''.join(answer), font, color, (cord[0] + size[0], cord[1]))
        screen.blit(mouse_cursor, pygame.mouse.get_pos())
        pygame.display.update()

def finished(block, password, list_blocks):
    return block == password or len(list_blocks) == 10

def how_to_play():
    button_how = Button('imagens/returntomenu_mouse.png', 'imagens/returntomenu.png', (522,0))
    
    while True:
        screen.blit(background_how, (0,0))     
        button_how.render(screen)
        
        for event in pygame.event.get():   
            if event.type == MOUSEBUTTONDOWN:
                if is_over(button_how):                    
                        return
            
        screen.blit(mouse_cursor, pygame.mouse.get_pos())
        pygame.display.update()  
            
def thegame():
    button_thegame = Button('imagens/returntomenu_mouse.png', 'imagens/returntomenu.png', (522,0))
    
    while True:
        screen.blit(background_thegame, (0,0))     
        button_thegame.render(screen)
        
        for event in pygame.event.get():   
            if event.type == MOUSEBUTTONDOWN:
                if is_over(button_thegame):                    
                        return
            
        screen.blit(mouse_cursor, pygame.mouse.get_pos())
        pygame.display.update()  
        
def credits():
    button_thegame = Button('imagens/returntomenu_mouse.png', 'imagens/returntomenu.png', (522,0))
    
    while True:
        screen.blit(background_credits, (0,0))     
        button_thegame.render(screen)
        
        for event in pygame.event.get():   
            if event.type == MOUSEBUTTONDOWN:
                if is_over(button_thegame):                    
                        return
            
        screen.blit(mouse_cursor, pygame.mouse.get_pos())
        pygame.display.update()
        
def multiplayer():
    
    buttons_mult ={}
    buttons_mult['button_returntomenu'] = Button('imagens/returntomenu_mouse.png', 'imagens/returntomenu.png', (522,0))
    buttons_mult['join'] = Button('imagens/join.png', 'imagens/join_mouse.png', (30, 200))
    buttons_mult['host'] = Button('imagens/host.png', 'imagens/host_mouse.png', (30, 250))
    font = pygame.font.SysFont('ocrb10', 35)

    while True:
        screen.blit(background, (0,0))         
        for button in buttons_mult.values():
            button.render(screen)
                
        for event in pygame.event.get():   
            if event.type == MOUSEBUTTONDOWN:
                if is_over(buttons_mult['button_returntomenu']):                    
                    return
                
                elif is_over(buttons_mult['join']):
                    sock = socket()
                    ip = input_display('IP: ', font, (255,0,0), (220,190))
                    port = input_display('Port: ', font, (255,0,0), (220,210))
                    try:
                        sock.connect((ip, int(port)))
                    except error:
                        print_display('Failed to try connect', font, (255,0,0), (220,250))
                        pygame.display.update()
                        sleep(4)
                        continue
                    
                    except TypeError and ValueError:
                        print_display('Invalid Port or IP', font, (255,0,0), (220,250))
                        pygame.display.update()
                        sleep(4)
                        continue
                    
                    print_display('Connected!', font, (255,0,0), (220,230))
    
                    pygame.display.update()
                    sleep(4)
                    sock.settimeout(10)
                    return sock    
                    
                elif is_over(buttons_mult['host']):
                    sock = socket()
                    ip = input_display('IP: ', font, (255,0,0), (100,190))
                    port = input_display('Port: ', font, (255,0,0), (220,210))                    
                    try:
                        sock.bind((ip, int(port)))                        
                    except error:
                        print_display('Failed to try connect', font, (255,0,0), (220,230))
                        sleep(4)
                        pygame.display.update()
                        continue
                    except TypeError and ValueError:
                        print_display('Invalid Port or IP', font, (255,0,0), (220,230))
                        pygame.display.update()
                        sleep(4)
                        continue
                    
                    sock.listen(1)
                    sock.settimeout(10)
                    try:
                        sock = sock.accept()[0]
                    except timeout:
                        print_display('Connect Failed!', font, (255,0,0), (220,230))
                        pygame.display.update()
                        sleep(4)
                        continue
                    print_display('Connected!', font, (255,0,0), (220,230))
    
                    pygame.display.update()
                    sleep(4)
                    sock.setblocking(True)
                    return sock
        screen.blit(mouse_cursor, pygame.mouse.get_pos())
        pygame.display.update()

def find_none(list_blocks):
    for block in list_blocks:   
        for i in xrange(len(block)):
            if block.get_pine(i) == None:
                return block, i   

def instatiation(cord):
    block = GraphicBlock(5, 'imagens/block.png', cord)
    block_choice1 = GraphicBlock(4, 'imagens/block_choice.png', (cord[0] + 20, cord[1] + 50))
    block_choice2 = GraphicBlock(4, 'imagens/block_choice.png', (cord[0] + 20, cord[1] + 90))
    
    for pine in GraphicPines.values():
        if not block_choice1.add_pine(pine, GraphicPines.values().index(pine)):
            block_choice2.add_pine(pine, GraphicPines.values().index(pine)-4)
    
    return block, block_choice1, block_choice2

def generate_password(size):
    password = GraphicBlock(size, 'imagens/block.png', (300, 700))
    GraphicPines_copy = GraphicPines.keys()
    
    for position in xrange(size):
        pine = choice(GraphicPines_copy)
        GraphicPines_copy.pop(GraphicPines_copy.index(pine))
        password.add_pine(GraphicPine(pine, 'imagens/pine_%s.png'% pine), position)
    return password

def create_password():
    password, block_choice1, block_choice2 = instatiation((30, 180))
    button_ok = Button('imagens/ok.png', 'imagens/ok_mouse.png', (300,220))
    list_blocks = [password, block_choice1, block_choice2]
    GraphicPine_mouse = None
    font = pygame.font.SysFont('ocrb10', 40, True) 
    
    while True:
        
        screen.blit(background, (0,0))
        button_ok.render(screen)
        print_display('Password: ', font, (255,0,0), (30, 140))
        for block in list_blocks:
            block.render(10, 'imagens/none.png', screen)
        for event in pygame.event.get():
            if event.type == MOUSEBUTTONDOWN:
                
                if is_over(button_ok):
                    if not password.contains(None):
                        password.render(10, 'imagens/none.png', screen)                           
                        return password
                    
                for i in xrange(5):
                    if password.get_pine(i) != None and is_over(password.get_pine(i)):
                      block_choice, position = find_none([block_choice1, block_choice2])
                      block_choice.add_pine(password.get_pine(i), position)
                      password.remove_pine(i)
                    
                    try:
                        if block_choice1.get_pine(i) != None and is_over(block_choice1.get_pine(i)):
                            GraphicPine_mouse = block_choice1.get_pine(i)
                            block_choice1.remove_pine(i)
                            
                        elif block_choice2.get_pine(i) != None and is_over(block_choice2.get_pine(i)):
                            GraphicPine_mouse = block_choice2.get_pine(i)
                            block_choice2.remove_pine(i)
                        
                    except 'InvalidPosition':
                        pass                   
                    
            if event.type == MOUSEBUTTONUP:
                    
                    if GraphicPine_mouse != None:
                        for i in xrange(5):
                            x, y = password.cord
                            cord = (10 + x + (pygame.image.load('imagens/none.png').convert_alpha().get_size()[0] + 10) * i), y
                            if is_over(GraphicPine(None,'imagens/none.png', cord)):
                                over = True
                                if not password.add_pine(GraphicPine_mouse, i):
                                    block_choice, position = find_none([block_choice1, block_choice2])
                                    block_choice.add_pine(GraphicPine_mouse, position)
                                break
                            over = False
                                
                        if not over:
                            block_choice, position = find_none([block_choice1, block_choice2])
                            block_choice.add_pine(GraphicPine_mouse, position)
                            
                        GraphicPine_mouse = None
                     
        if GraphicPine_mouse != None:
            x, y = pygame.mouse.get_pos()
            w, h = GraphicPine_mouse.image.get_size()
            screen.blit(GraphicPine_mouse.image, (x - w/2, y - h/2) )
        screen.blit(mouse_cursor, pygame.mouse.get_pos())
        pygame.display.update()  
        
def receive(password):
    print 'entrou'
    inf = sock.recv(100)
    inf = ''        
    inf = inf.split()
    block = Block(len(inf))
    for i in xrange(len(inf)):
        pine = Pine(inf[i])
        block.add_pine(pine, i)
    result = block.result_block(password)
    sock.sendall(str(result))

def play(size, multiplayer=False):

    if multiplayer:
        password = create_password()
    else:    
        password = generate_password(size)
    block, block_choice1, block_choice2 = instatiation((200, 140))
    
    buttons_play = {}
    buttons_play['try'] = Button('imagens/try.png', 'imagens/try_mouse.png', (block.cord[0] + 320, block.cord[1]))
    buttons_play['returntomenu'] = Button('imagens/returntomenu.png', 'imagens/returntomenu_mouse.png', (0,0))
    
    list_blocks = []

    font = pygame.font.SysFont('ocrb10', 60, True)
    font_small = pygame.font.SysFont('ocrb10', 40, True)
        
    button_pressed = None
    GraphicPine_mouse = None
    
    while True:
        
        if multiplayer:
            t = Timer(1, receive(password))
            t.start()
        screen.blit(background_play, (0,0))
        screen.blit(pygame.image.load('imagens/hints.png').convert_alpha(), (520, 70))
        
        num = 1
        for block_old, block_result in list_blocks:
            
            print_display(str(num), font, (50,255,0), (block_old.cord[0] - 120, block_old.cord[1]))
            
            block_old.render(10, 'imagens/none.png', screen)
            block_result.render(5, 'imagens/result_none.png', screen)
            num += 1
        if not multiplayer and not finished(block, password, list_blocks):
            block.render(10, 'imagens/none.png', screen)
            block_choice1.render(10, 'imagens/none.png', screen)
            block_choice2.render(10, 'imagens/none.png', screen)
        elif multiplayer:
            block.render(10, 'imagens/none.png', screen)
            block_choice1.render(10, 'imagens/none.png', screen)
            block_choice2.render(10, 'imagens/none.png', screen)
        else:
            del buttons_play['try']
            button_pressed = None
            if len(list_blocks) == 10:
                print_display('You Lose!', font, (50,255,0), (240, 80))
                print_display('Password:', font, (50,255,0), (210, 650))
                password.render(10, 'imagens/none.png', screen)
                
            else:
                print_display('You Win', font, (50,255,0), (240,80))
        
        for button in buttons_play.values():
            button.render(screen)
        
        for event in pygame.event.get():
            
            if event.type == MOUSEBUTTONDOWN:
                
                for i in xrange(5):
                    if block.get_pine(i) != None and is_over(block.get_pine(i)):
                      block_choice, position = find_none([block_choice1, block_choice2])
                      block_choice.add_pine(block.get_pine(i), position)
                      block.remove_pine(i)
                    
                    try:
                        if block_choice1.get_pine(i) != None and is_over(block_choice1.get_pine(i)):
                            GraphicPine_mouse = block_choice1.get_pine(i)
                            block_choice1.remove_pine(i)
                            
                        elif block_choice2.get_pine(i) != None and is_over(block_choice2.get_pine(i)):
                            GraphicPine_mouse = block_choice2.get_pine(i)
                            block_choice2.remove_pine(i)
                        
                    except 'InvalidPosition':
                        pass                   
                
                for button_name, button in buttons_play.iteritems():
                    if is_over(button):
                        button_pressed = button_name                    
                        break
            
            if event.type == MOUSEBUTTONUP:
                
                if GraphicPine_mouse != None:
                    for i in xrange(5):
                        x, y = block.cord
                        cord = (10 + x + (pygame.image.load('imagens/none.png').convert_alpha().get_size()[0] + 10) * i), y
                        if is_over(GraphicPine(None,'imagens/none.png', cord)):
                            over = True
                            if not block.add_pine(GraphicPine_mouse, i):
                                block_choice, position = find_none([block_choice1, block_choice2])
                                block_choice.add_pine(GraphicPine_mouse, position)
                            break
                        over = False
                            
                    if not over:
                        block_choice, position = find_none([block_choice1, block_choice2])
                        block_choice.add_pine(GraphicPine_mouse, position)
                        
                    GraphicPine_mouse = None
        
                        
        if button_pressed == 'try':       
            if not block.contains(None) and not finished(block, password, list_blocks):
                if not multiplayer:
                    result_block = block.result_block(password)
                else:
                    sock.sendall(str(block))
                    while True:
                        try:
                            result = sock.recv(1024)
                            break
                        except:
                            continue
                        
                    result = result.split()
                    result_block = GraphicBlock(len(result), 'imagens/block_result.png')
                    result_block.cord = (block.cord[0] + 320, block.cord[1])
                    for i in xrange(len(result)):
                        result_block.add_pine(GraphicPine(result[i], 'imagens/pine_%s.png'%result[i], i))    
                        result_block.get_pine(i).cord = (block.cord[0] + 5 + (block.get_pine(i).get_size()[0] + 5) * i, block.cord[1])
                list_blocks.append((block.copy('imagens/block.png'), result_block.copy('imagens/block_result.png')))
                block, block_choice1, block_choice2 = instatiation((block.cord[0], block.cord[1]+50))
                buttons_play['try'].cord = (buttons_play['try'].cord[0], buttons_play['try'].cord[1] + 50)
                button_pressed = None
                          
        elif button_pressed == 'returntomenu':
            return      
        elif GraphicPine_mouse != None:
            x, y = pygame.mouse.get_pos()
            w, h = GraphicPine_mouse.image.get_size()
            screen.blit(GraphicPine_mouse.image, (x - w/2, y - h/2) )
        screen.blit(mouse_cursor, pygame.mouse.get_pos())
        pygame.display.update()  



while True:
    
    screen.blit(background, (0,0))
    for button in buttons.values():
        button.render(screen)
    screen.blit(mouse_cursor, pygame.mouse.get_pos())
                    
    for event in pygame.event.get():                       
        if event.type == QUIT:
                exit()    
        if event.type == MOUSEBUTTONDOWN:   
            for button_name, button in buttons.iteritems():
                if is_over(button):
                    button_pressed = button_name                    
                    break
        
    if button_pressed is not None:
        if button_pressed == 'single_player':
            play(5)
        elif button_pressed == 'multi_player':
            sock = multiplayer()
            if sock != None:
                play(5, True)
        elif button_pressed == 'credits':
            credits()
        elif button_pressed == 'how_to_play':
           how_to_play()
        elif button_pressed == 'thegame':
            thegame()
        elif button_pressed == 'quit':
            exit()
    button_pressed = None                      
    
    pygame.display.update()
